package com.ruoyi.js.controller;

import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.json.JSONObject;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.js.domain.*;
import com.ruoyi.js.service.*;
import com.ruoyi.js.utils.ScoreUtils;
import com.ruoyi.js.webscoket.WebSocketUsers;
import com.ruoyi.system.service.ISysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 分数 Controller
 * 
 * @author greejoy
 * @date 2021-07-01
 */
@Controller
@RequestMapping("/js/score")
public class JsScoreController extends BaseController
{
    private String prefix = "js/score";

    @Autowired
    ServletContext servletContext;

    @Autowired
    private IJsScoreService jsScoreService;

    @Autowired
    private IJsMatchService jsMatchService;

    @Autowired
    private IJsItemService jsItemService;

    @Autowired
    private IJsRegisterService jsRegisterService;

    @Autowired
    private IJsPlaceService jsPlaceService;

    @Autowired
    private IJsMatchValueService jsMatchValueService;

    @Autowired
    private IJsJudgeService jsJudgeService;

    @Autowired
    private IJsScoreQueueService jsScoreQueueService;

    @Autowired
    private ISysConfigService configService;

    @Value(value = "${js.app.httpUrl}")
    private String httpUrl;

    @Value(value = "${js.app.wsUrl}")
    private String wsUrl;

    @GetMapping("/record")
    public String record(@CookieValue("app_match_id") Long matchId, HttpServletRequest request, ModelMap mmap)
    {
        JsMatch curMatch = jsMatchService.selectJsMatchById(matchId);
        mmap.put("curMatch", curMatch);

        mmap.put("httpUrl", httpUrl);
        mmap.put("wsUrl", wsUrl);

        List<JsPlace> placeList = jsPlaceService.selectJsPlaceList(null);
        mmap.put("placeList", placeList);

        return prefix + "/record";
    }

    @GetMapping("/getRegisterList")
    @ResponseBody
    public AjaxResult getRegisterList(@CookieValue("app_match_id") Long matchId, Long placeId)
    {
        JsRegister q_r = new JsRegister(matchId);
        q_r.setPlaceId(placeId);
        List<JsRegister> registerList = jsRegisterService.selectJsRegisterListToMatch(q_r);
        return AjaxResult.success(registerList);
    }


    @GetMapping("/getRegisterInfo")
    @ResponseBody
    public AjaxResult getRegisterInfo(@CookieValue("app_match_id") Long matchId, Long registerId)
    {
        Map result = new HashMap();

        JsRegister register = jsRegisterService.selectJsRegisterById(registerId);

        if(register == null){
            throw new BusinessException("没有报名信息，请联系系统管理员！");
        }

        result.put("register", register);

        JsItem item = jsItemService.selectJsItemById(register.getItemId());
        List<JsMatchValue> matchValueList = jsMatchValueService.selectJsMatchValueList(new JsMatchValue(item.getId()));

        result.put("matchValueList", matchValueList);

        JsPlace place = jsPlaceService.selectJsPlaceById(register.getPlaceId());

        List<JsJudge> judgeList = jsJudgeService.selectJsJudgeListByIds(place.getJudgeIds());
        result.put("judgeList", judgeList);

        return AjaxResult.success(result);
    }


    @GetMapping("/getRegisterScore")
    @ResponseBody
    public AjaxResult getRegisterScore(@CookieValue("app_match_id") Long matchId, Long registerId)
    {
        Map result = new HashMap();

        JsRegister register = jsRegisterService.selectJsRegisterById(registerId);
        if(register == null){
            throw new BusinessException("没有报名信息，请联系系统管理员！");
        }

        List<JsScore> scoreList = jsScoreService.selectJsScoreList(new JsScore(register.getId(), null, null));

        Double valueScore = ScoreUtils.computeRegisterScore(scoreList);
        result.put("valueScore", valueScore);

        Map<String, Double> scoreMap = scoreList.stream().collect(Collectors.toMap(m -> m.getMatchValueId() + "-" + m.getJudgeId(), JsScore::getValue));

        result.put("scoreMap", scoreMap);

        return AjaxResult.success(result);
    }


    @PostMapping("/saveScore")
    @ResponseBody
    public AjaxResult saveScore(JsScore score)
    {

        List<JsScore> scoreList = jsScoreService.selectJsScoreList(new JsScore(score.getRegisterId(), score.getMatchValueId(), score.getJudgeId()));
        if(scoreList.size() > 0){
            String ids = scoreList.stream().map(m -> m.getId().toString()).collect(Collectors.joining(","));
            jsScoreService.deleteJsScoreByIds(ids);
        }

        if(score.getValue() != null){
            jsScoreService.insertJsScore(score);
        }

        // 是否已经完成所有裁判打分
        if(jsRegisterService.checkAllJudgeScored(score.getRegisterId())){
            // ws发送完成打分通知
            JSONObject object = new JSONObject();
            object.set("type", "finishScore");
            object.set("registerId", score.getRegisterId());
            WebSocketUsers.sendMessageToUsersByText(object.toCompactString());
        }

        return AjaxResult.success();
    }


    @GetMapping("/sendToScore")
    @ResponseBody
    public AjaxResult sendToScore(Long registerId)
    {
        JsRegister register = jsRegisterService.selectJsRegisterById(registerId);
        JsPlace place = jsPlaceService.selectJsPlaceById(register.getPlaceId());
        List<JsJudge> judgeList = jsJudgeService.selectJsJudgeListByIds(place.getJudgeIds());

        // 删除报名已有队列
        jsScoreQueueService.deleteJsScoreQueueByRegisterId(registerId);
        for (JsJudge judge : judgeList) {
            jsScoreQueueService.deleteJsScoreQueueByJudgeId(judge.getId());
        }

        // 添加新队列
        for (JsJudge judge : judgeList) {
            jsScoreQueueService.insertJsScoreQueue(new JsScoreQueue(registerId, judge.getId()));
        }

        // 发送打分信息
        List<Long> judgeIds = judgeList.stream().map(JsJudge::getId).collect(Collectors.toList());
        JSONObject object = new JSONObject();
        object.set("type", "judgeScore");
        object.set("judgeIds", judgeIds);
        WebSocketUsers.sendMessageToUsersByText(object.toCompactString());


        // 发送投屏信息
        object = new JSONObject();
        object.set("type", "screenScore");
        object.set("registerId", registerId);
        object.set("placeId", register.getPlaceId());
        WebSocketUsers.sendMessageToUsersByText(object.toCompactString());

        return AjaxResult.success();
    }

    @PostMapping("/clearRegisterScore")
    @ResponseBody
    public AjaxResult clearRegisterScore(Long registerId)
    {
        JsRegister register = jsRegisterService.selectJsRegisterById(registerId);
        register.setIsScored(false);
        jsRegisterService.updateJsRegister(register);

        List<JsScore> scoreList = jsScoreService.selectJsScoreList(new JsScore(registerId, null, null));
        String scoreIds = scoreList.stream().map(s -> s.getId().toString()).collect(Collectors.joining(","));
        jsScoreService.deleteJsScoreByIds(scoreIds);

        return AjaxResult.success();
    }

    @PostMapping("/updateRemark")
    @ResponseBody
    public AjaxResult updateRemark(Long registerId, String remark)
    {
        JsRegister register = jsRegisterService.selectJsRegisterById(registerId);
        register.setRemark(remark);
        jsRegisterService.updateJsRegister(register);
        return AjaxResult.success();
    }

    @GetMapping("/screenList")
    public String screenList(@CookieValue("app_match_id") Long matchId, ModelMap mmap)
    {
        List<JsPlace> placeList = jsPlaceService.selectJsPlaceList(new JsPlace(matchId));
        mmap.put("placeList", placeList);

        return prefix + "/screenList";
    }

    @GetMapping("/sendToScreenScore")
    @ResponseBody
    public AjaxResult sendToScreenScore(Long registerId)
    {
        JSONObject object = new JSONObject();
        object.set("type", "screenScore");
        object.set("registerId", registerId);

        JsRegister register = jsRegisterService.selectJsRegisterById(registerId);
        object.set("placeId", register.getPlaceId());

        // 发送投屏信息
        WebSocketUsers.sendMessageToUsersByText(object.toCompactString());

        return AjaxResult.success();
    }


    @GetMapping("/sendToScreenScore2")
    @ResponseBody
    public AjaxResult sendToScreenScore2(Long registerId)
    {
        JSONObject object = new JSONObject();
        object.set("type", "screenScore2");
        object.set("registerId", registerId);

        JsRegister register = jsRegisterService.selectJsRegisterById(registerId);
        object.set("placeId", register.getPlaceId());

        // 发送投屏信息
        WebSocketUsers.sendMessageToUsersByText(object.toCompactString());

        return AjaxResult.success();
    }


    @GetMapping("/screenScore")
    public String screenScore(Long placeId, ModelMap mmap)
    {
        JsMatch match = jsMatchService.getCurrentScoreMatch();
        mmap.put("match", match);

        mmap.put("wsUrl", wsUrl);
        mmap.put("placeId", placeId);

        return prefix + "/screenScore";
    }


    // 返回当前各个裁判选手打分成绩
    @GetMapping("/getScreenRegisterData")
    @ResponseBody
    public AjaxResult getScreenRegisterData(Long registerId) {
        Map result = new HashMap();

        JsRegister register = jsRegisterService.selectJsRegisterById(registerId);

        result.put("register", register);

        List<JsScore> scoreList = jsScoreService.selectJsScoreList(new JsScore(register.getId(), null, null));
        Double valueScore = ScoreUtils.computeRegisterScore(scoreList);
        result.put("valueScore", valueScore);

        Map<Long, List<JsScore>> scoreListMap = scoreList.stream().collect(Collectors.groupingBy(JsScore::getJudgeId));
        boolean allScored = true;
        JsPlace place = jsPlaceService.selectJsPlaceById(register.getPlaceId());
        List<JsJudge> judgeList = jsJudgeService.selectJsJudgeListByIds(place.getJudgeIds());
        for (JsJudge judge : judgeList) {
            List<JsScore> list = scoreListMap.get(judge.getId());
            if(list != null){
                Double score = list.stream().map(JsScore::getValue).reduce((sum, value) -> sum += value).orElse(null);
                judge.setScore(score);
                judge.setScoreList(list);
                if(score == null || score == 0){
                    allScored = false;
                }
            }
        }
        result.put("judgeList", judgeList);
        result.put("allScored", allScored);

        return AjaxResult.success(result);
    }


    @GetMapping("/getScreenSessionData")
    @ResponseBody
    public AjaxResult getScreenSessionData(Long registerId) {
        Map result = new HashMap();

        JsRegister register = jsRegisterService.selectJsRegisterById(registerId);

        result.put("register", register);

        List<JsRegisterScore> registerScoreList = buildItemScoreRankingList(register.getItemId());


        // 返回同场地本轮所有选手成绩
        registerScoreList = registerScoreList.stream().filter(f -> f.getPlaceId().equals(register.getPlaceId()) && f.getSession().equals(register.getSession())).collect(Collectors.toList());

        registerScoreList.sort(Comparator.comparing(JsRegisterScore::getOdr));

        result.put("registerScoreList", registerScoreList);

        return AjaxResult.success(result);
    }

    @GetMapping("/screenRanking")
    public String screenRanking(Long placeId, ModelMap mmap)
    {
        JsMatch match = jsMatchService.getCurrentScoreMatch();
        mmap.put("match", match);

        mmap.put("wsUrl", wsUrl);
        mmap.put("placeId", placeId);

        return prefix + "/screenRanking";
    }

    @GetMapping("/getScreenRankingData")
    @ResponseBody
    public AjaxResult getScreenRankingData(Long registerId) {
        Map result = new HashMap();

        JsRegister register = jsRegisterService.selectJsRegisterById(registerId);

        result.put("register", register);

        List<JsRegisterScore> registerScoreList = buildItemScoreRankingList(register.getItemId());

        registerScoreList = registerScoreList.stream().filter(f -> f.getRanking() != null).collect(Collectors.toList());

        result.put("registerScoreList", registerScoreList);

        return AjaxResult.success(result);
    }


    @GetMapping("/query")
    public String query(@CookieValue("app_match_id") Long matchId, ModelMap mmap)
    {
        List<JsItem> itemList = jsItemService.selectJsItemList(new JsItem(matchId));
        mmap.put("itemList", itemList);

        return prefix + "/query";
    }

    /**
     * 查询分数 列表
     */
    @PostMapping("/list")
    @ResponseBody
    public TableDataInfo list(Long itemId, String playerName)
    {
        List<JsRegisterScore> registerScoreList = buildItemScoreRankingList(itemId);
        if(StringUtils.isNotEmpty(playerName)){
            registerScoreList = registerScoreList.stream().filter(f -> f.getPlaceName().contains(playerName)).collect(Collectors.toList());
        }
        return getDataTable(registerScoreList);
    }


    /**
     * 导出成绩
     */
    @PostMapping("/exportScore")
    @ResponseBody
    public AjaxResult exportScore(Long itemId)
    {
        if(itemId == null){
            return AjaxResult.error("未选择小项");
        }

        List<JsRegisterScore> registerScoreList = buildItemScoreRankingList(itemId);
        ExcelUtil<JsRegisterScore> util = new ExcelUtil<JsRegisterScore>(JsRegisterScore.class);

        return util.exportExcel(registerScoreList, "比赛成绩");
    }

    // 计算并构造排名成绩数据
    private List<JsRegisterScore> buildItemScoreRankingList(Long itemId) {
        List<JsRegisterScore> registerScoreList = new ArrayList<>();

        if (itemId == null) {
            throw new BusinessException("项目不能为空");
        }

        JsRegister q_r = new JsRegister();
        q_r.setItemId(itemId);
        List<JsRegister> registerList = jsRegisterService.selectJsRegisterList(q_r);
        String ids = registerList.stream().map(m -> m.getId().toString()).collect(Collectors.joining(","));
        List<JsScore> scoreList = jsScoreService.selectJsScoreListByRegisterIds(ids);
        Map<Long, List<JsScore>> scoreListMap = scoreList.stream().collect(Collectors.groupingBy(JsScore::getRegisterId));

        for (JsRegister register : registerList) {
            JsRegisterScore registerScore = new JsRegisterScore();
            registerScore.setRegisterId(register.getId());
            registerScore.setItemId(register.getItemId());
            registerScore.setItemName(register.getItemName());
            registerScore.setPlayerName(register.getPlayerName());
            registerScore.setPlayerIdcard(register.getPlayerIdcard());
            registerScore.setPlaceId(register.getPlaceId());
            registerScore.setPlaceName(register.getPlaceName());
            registerScore.setSession(register.getSession());
            registerScore.setOdr(register.getOdr());
            registerScore.setWorksName(register.getWorksName());

            List<JsScore> list = scoreListMap.get(register.getId());
            if(list != null){
                registerScore.setScoreList(list);
                Double valueScore = ScoreUtils.computeRegisterScore(list);
                registerScore.setValueScore(valueScore);
                Double remarkScore = StringUtils.isNotEmpty(register.getRemark()) ? Double.valueOf(register.getRemark()) : 0d;
                registerScore.setRemarkScore(remarkScore);
                Double finalScore = valueScore + remarkScore;
                registerScore.setFinalScore(finalScore);
            }else {
                registerScore.setValueScore(0d);
                registerScore.setRemarkScore(0d);
                registerScore.setFinalScore(0d);
            }
            registerScoreList.add(registerScore);
        }

        ScoreUtils.computeScoreRanking(registerScoreList);

        for (JsRegisterScore registerScore : registerScoreList) {
            if(registerScore.getFinalScore().equals(0)){
                registerScore.setRanking(null);
            }
        }

        return  registerScoreList;
    }

}
